﻿using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.RegularExpressions;
using DimensionsHelper.Common.Utils;
using DimensionsHelper.LanguageService.Protocol;
using DimensionsHelper.LanguageService.Symbols;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService;

/// <summary>
///     一类简单的表达式转换器。
///     在一些情况下，表达式符号之间允许隐式转换，例如：
///     在元数据上下文中，标识符和字符串在一些情况下可以互相转换，
///     <code>
/// Field_Name "" long;
/// </code>
///     和
///     <code>
/// "Field_Name" "" long;
/// </code>
///     是等价的。
///     在计算常量表达式时，字符串可以隐式转换为另一种类型。
/// </summary>
public abstract class ExpressionConverter
{
    private static readonly SyntaxKinds[] ArithmeticOperatorKinds =
    [
        SyntaxKinds.PlusToken,
        SyntaxKinds.MinusToken,
        SyntaxKinds.AsteriskToken,
        SyntaxKinds.SlashToken
    ];


    /// <summary>
    ///     标识符转换器，标识符只能转换为字符串。
    /// </summary>
    private static ExpressionConverter IdentifierConverter => new IdentifierConverter();


    /// <summary>
    ///     字符串表达式转换器，支持字符串类型向其他常量表达式的转换。
    /// </summary>
    public static ExpressionConverter StringLiteralConverter => new StringLiteralConverter();


    /// <summary>
    ///     整型数字常量的表达式转换器，支持整数表达式向其他常量的转换。
    /// </summary>
    public static ExpressionConverter IntegerLiteralConverter => new IntegerLiteralConverter();


    /// <summary>
    ///     双精度浮点数常量的表达式转换器，支持浮点数常量向其他常量的转换。
    /// </summary>
    public static ExpressionConverter DoubleLiteralConverter => new DoubleLiteralConverter();


    /// <summary>
    ///     布尔值常量的表达式转换器，支持布尔值向字符串和数字常量的转换。
    /// </summary>
    public static ExpressionConverter BooleanLiteralConverter => new BooleanLiteralConverter();


    /// <summary>
    ///     Null字面量的表达式转换器。
    /// </summary>
    public static ExpressionConverter NullConverter => new NullConverter();


    /// <summary>
    ///     Any通用类型的表达式转换器。
    /// </summary>
    private static ExpressionConverter AnyConverter => new AnyConverter();

    /// <summary>
    ///     如果此节点可以转换为目标类型，返回<see langword="true" />。
    /// </summary>
    /// <param name="source">原始表达式</param>
    /// <param name="targetKind">目标语法类型</param>
    /// <param name="result">转换后的节点</param>
    public abstract bool TryConvert(Expression source, SyntaxKinds targetKind,
        [MaybeNullWhen(false)] out Expression result);


    /// <summary>
    ///     判断给定的表达式是否可以转换为日期类型常量。
    /// </summary>
    /// <param name="source">原始表达式</param>
    private static bool IsDateConvertible(Expression source)
    {
        // 整数和浮点数可以转换为时间戳
        if (source.IsOneOfNode(SyntaxKinds.Integer, SyntaxKinds.Double) ||
            NodeConverter.TryConvertNegativeDouble(source, out _))
        {
            return true;
        }

        if (!source.IsNode(SyntaxKinds.String))
        {
            return false;
        }

        // 字符串常量尝试转换成正整数或日期字符串
        string strValue = ((StringLiteral)source).Value;
        return double.TryParse(strValue, out _) || DateTime.TryParse(strValue, out _);
    }


    /// <summary>
    ///     如果此节点可以转换为目标类型，返回<see langword="true" />。
    /// </summary>
    /// <param name="source">原始表达式</param>
    /// <param name="targetType">目标值类型</param>
    public virtual bool IsConvertible(Expression source, ValueTypeSymbol targetType)
    {
        return targetType switch
        {
            { Name: "Long" } => TryConvert(source, SyntaxKinds.Integer, out _),
            { Name: "Double" } => TryConvert(source, SyntaxKinds.Double, out _),
            { Name: "Boolean" } => TryConvert(source, SyntaxKinds.Boolean, out _),
            { Name: "Date" } => IsDateConvertible(source),
            _ => false
        };
    }


    public static bool IsArithmeticOperatorKind(SyntaxKinds kind)
    {
        return ArithmeticOperatorKinds.Contains(kind);
    }


    /// <summary>
    ///     推断指定右值和转换器类型进行数学计算后的类型符号。
    ///     只支持值类型符号
    /// </summary>
    /// <param name="left">左值表达式</param>
    /// <param name="right">右值表达式</param>
    /// <param name="rightSymbol">右值符号</param>
    /// <param name="operatorKind">运算符类型</param>
    /// <param name="result">运算后的结果类型</param>
    public abstract bool ComputeArithmeticOperation(Expression left, Expression right, ITypeSymbol rightSymbol,
        SyntaxKinds operatorKind, [MaybeNullWhen(false)] out ITypeSymbol result);


    /// <summary>
    ///     选择指定常量表达式类型的语法节点转换器。如果没有合适的，返回<see langword="null" />。
    /// </summary>
    /// <param name="kind">当前数据的语法类型</param>
    public static ExpressionConverter SelectConverter(SyntaxKinds kind)
    {
        return kind switch
        {
            SyntaxKinds.Identifier => IdentifierConverter,
            SyntaxKinds.String => StringLiteralConverter,
            SyntaxKinds.Integer => IntegerLiteralConverter,
            SyntaxKinds.Double => DoubleLiteralConverter,
            SyntaxKinds.Boolean => BooleanLiteralConverter,
            SyntaxKinds.Null => NullConverter,
            _ => AnyConverter
        };
    }


    /// <summary>
    ///     获取指定值类型符号的表达式类型转换器。
    /// </summary>
    /// <param name="symbol">值类型符号</param>
    public static ExpressionConverter? SelectConverter(ValueTypeSymbol symbol)
    {
        return symbol switch
        {
            { Name: "String" } => StringLiteralConverter,
            { Name: "Long" } => IntegerLiteralConverter,
            { Name: "Double" } or { Name: "Date" } => DoubleLiteralConverter,
            { Name: "Boolean" } => BooleanLiteralConverter,
            { Name: "Null" } => NullConverter,
            { Name: "Any" } => AnyConverter,
            _ => null
        };
    }
}


/**
 * Date -> Long, Double
 * Operation occurs on the date's double value representation.
 * If the operation involves an invalid date, '####' is returned.
 * 
 * 
 * '+' Operator
 * +-------------+----------------+-------------------+--------------------+--------------------+----------------+
 * |             | Double         | Long              | Text               | Categorical        | Date           |
 * |-------------+----------------+-------------------+--------------------+--------------------+----------------|
 * | Double      | Add Double     | Add Double        | Add Double         | Not applicable     | Add Date       |
 * | Long        | Add Double     | Add Long          | Add Long           | Union Categorical  | Add Date       |
 * | Text        | Add Double     | Add Double        | Concatenation Text | Union Categorical  | Add Date       |
 * | Categorical | Not applicable |	Union Categorical | Union Categorical  | Union Categorical  | Not applicable |
 * | Date        | Add Date       | Add Date          | Add Date           | Not applicable     | Add Date       |
 * +-------------------------------------------------------------------------------------------------------------+
 * 
 * '-' Operator
 * +------------------------------------------------------------------------------------------------------------------+
 * |             | Double          | Long	              | Text                | Categorical         | Date          |
 * |-------------+-----------------+----------------------+---------------------+---------------------+---------------+
 * | Double	     | Subtract Double | Subtract Double      | Subtract Double	    | Not applicable      | Subtract2 Date|
 * | Long        | Subtract Double | Subtract Long        | Subtract Long       | Subtract Categorical|	Subtract2 Date|
 * | Text        | Subtract Double | Subtract Double      | Not applicable      | Subtract Categorical|	Subtract4 Date|
 * | Categorical | Not applicable  | Subtract Categorical | Subtract Categorical| Subtract Categorical|	Not applicable|
 * | Date        | Subtract Date   | Subtract Date	      | Subtract Date       | Not applicable      | Subtract Date |
 * +------------------------------------------------------------------------------------------------------------------+
 */
internal class IdentifierConverter : ExpressionConverter
{
    public override bool TryConvert(Expression source,
        SyntaxKinds targetKind,
        [MaybeNullWhen(false)] out Expression result)
    {
        Debug.Assert(source.IsNode(SyntaxKinds.Identifier));

        // 标识符只能转换为字符串
        if (targetKind == SyntaxKinds.String)
        {
            result = NodeConverter.ToString(source);
            return true;
        }

        result = null;
        return false;
    }


    public override bool IsConvertible(Expression source,
        ValueTypeSymbol targetType)
    {
        return ValueTypeSymbol.IsString(targetType) && TryConvert(source, SyntaxKinds.String, out _);
    }


    public override bool ComputeArithmeticOperation(
        Expression left,
        Expression right,
        ITypeSymbol rightSymbol,
        SyntaxKinds operatorKind,
        [MaybeNullWhen(false)] out ITypeSymbol result)
    {
        result = null;
        return false;
    }
}


internal partial class StringLiteralConverter : ExpressionConverter
{
    [GeneratedRegex(@"([a-zA-Z_@#\$][a-zA-Z0-9_@#\$]*)|(\d+)")]
    private static partial Regex CategoryValueRegex();


    private static bool TryConvertToCategory(string value, int startPos, DocumentUri uri,
        [MaybeNullWhen(false)] out CategoryLiteral result)
    {
        result = null;
        Match match = CategoryValueRegex().Match(value);
        if (!match.Success)
        {
            return false;
        }

        // Name
        if (!string.IsNullOrEmpty(match.Groups[0].Value))
        {
            Group idGroup = match.Groups[0];
            Identifier id = NodeFactory.CreateIdentifier(idGroup.Value);
            id.Update(startPos + idGroup.Index, idGroup.Length);
            id.SetUri(uri);

            result = NodeFactory.CreateCategoryLiteral(null, null, id,
                null, null);
            result.UpdateFrom(id);
            return true;
        }

        // Integer
        if (string.IsNullOrEmpty(match.Groups[1].Value))
        {
            return false;
        }

        Group group = match.Groups[1];
        IntegerLiteral integer = NodeFactory.CreateIntegerLiteral(null, int.Parse(group.Value));

        integer.Update(startPos + group.Index, group.Length, group.Value);
        integer.SetUri(uri);

        result = NodeFactory.CreateCategoryLiteral(null, integer);
        result.UpdateFrom(integer);
        return true;
    }


    private static bool TryConvertToCategorical(StringLiteral source,
        [MaybeNullWhen(false)] out CategoricalLiteral result)
    {
        result = null;

        string categories = source.Value;
        int pos = source.Start;

        SyntaxToken? leftCurly = null;
        SyntaxToken? rightCurly = null;

        if (categories.StartsWith('{') && categories.EndsWith('}'))
        {
            leftCurly = NodeFactory.CreateSyntaxToken(SyntaxKinds.LeftCurlyToken);
            leftCurly.Update(source.Start, 1, "{");
            leftCurly.SetUri(source.Uri);

            rightCurly = NodeFactory.CreateSyntaxToken(SyntaxKinds.RightCurlyToken);
            rightCurly.Update(source.End - 1, 1, "}");
            rightCurly.SetUri(source.Uri);

            categories = categories[1..^1];
            pos++;
        }

        List<CategoryLiteral> items = [];

        foreach (string? element in categories.Split(','))
        {
            if (!string.IsNullOrWhiteSpace(element))
            {
                if (TryConvertToCategory(element, pos, source.Uri, out CategoryLiteral? category))
                {
                    items.Add(category);
                }
                else
                {
                    return false;
                }
            }

            pos += element.Length + 1;
        }

        result = NodeFactory.CreateCategoricalLiteral(null, leftCurly, rightCurly, items);
        result.UpdateFrom(source);
        return true;
    }


    public override bool TryConvert(Expression source, SyntaxKinds targetKind,
        [MaybeNullWhen(false)] out Expression result)
    {
        result = null;
        if (!source.IsNode(SyntaxKinds.String) || !SyntaxFacts.IsLiteralKind(targetKind))
        {
            return false;
        }

        StringLiteral str = (StringLiteral)source;

        switch (targetKind)
        {
            case SyntaxKinds.String:
            {
                result = str;
                return true;
            }

            case SyntaxKinds.Integer:
            {
                string strValue = str.Value;
                int integerValue = int.MinValue;
                // 可能是八进制或十六进制数字
                if (strValue.Length > 2)
                {
                    if (strValue.StartsWith("&H", StringComparison.OrdinalIgnoreCase) &&
                        !int.TryParse(strValue[2..], NumberStyles.HexNumber, CultureInfo.InvariantCulture,
                            out integerValue))
                    {
                        return false;
                    }

                    if (strValue.StartsWith("&O", StringComparison.OrdinalIgnoreCase) &&
                        !strValue[2..].TryParseOctalNumber(out integerValue))
                    {
                        return false;
                    }
                }

                if (integerValue == int.MinValue && !int.TryParse(strValue.Trim(), out integerValue))
                {
                    return false;
                }

                result = NodeConverter.ToInteger(source, integerValue);
                break;
            }

            case SyntaxKinds.Double:
            {
                if (!double.TryParse(str.Value.Trim(), out double doubleValue))
                {
                    return false;
                }

                result = NodeConverter.ToDouble(source, doubleValue);
                break;
            }

            case SyntaxKinds.Boolean:
            {
                if (!bool.TryParse(str.Value.Trim(), out bool boolValue))
                {
                    return false;
                }

                result = NodeConverter.ToBoolean(source, boolValue);
                break;
            }

            // 字符串转换成分类值时，开头和结尾可以有花括号或没有花括号。
            // 分类值的有效值是标识符或整数。
            case SyntaxKinds.Categorical:
            {
                if (!TryConvertToCategorical(str, out CategoricalLiteral? categorical))
                {
                    return false;
                }

                result = categorical;
                break;
            }
        }

        if (result != null && result != source)
        {
            result.UpdateFrom(source);
        }

        return result != null;
    }

    public override bool IsConvertible(Expression source, ValueTypeSymbol targetType)
    {
        return targetType switch
        {
            { Name: "Long" } => TryConvert(source, SyntaxKinds.Integer, out _),
            { Name: "Double" } => TryConvert(source, SyntaxKinds.Double, out _),
            { Name: "Boolean" } => TryConvert(source, SyntaxKinds.Boolean, out _),
            { Name: "Categorical" } => TryConvert(source, SyntaxKinds.Categorical, out _),
            { Name: "String" } => TryConvert(source, SyntaxKinds.String, out _),
            _ => false
        };
    }

    public override bool ComputeArithmeticOperation(
        Expression left,
        Expression right,
        ITypeSymbol rightSymbol,
        SyntaxKinds operatorKind,
        [MaybeNullWhen(false)] out ITypeSymbol result)
    {
        result = null;

        if (ValueTypeSymbol.IsAnyOrNull(rightSymbol))
        {
            result = ValueTypeSymbol.String;
            return true;
        }

        // 两个字符串之间，只支持'+'
        if (ValueTypeSymbol.IsString(rightSymbol))
        {
            result = ValueTypeSymbol.String;
            return operatorKind == SyntaxKinds.PlusToken;
        }

        // 对于'*'和'/'，支持数字和Categorical
        if (operatorKind is not (SyntaxKinds.AsteriskToken or SyntaxKinds.SlashToken or SyntaxKinds.MinusToken))
        {
            return false;
        }

        if (!ReferenceEquals(rightSymbol, ValueTypeSymbol.Long) &&
            !ReferenceEquals(rightSymbol, ValueTypeSymbol.Double) &&
            !ReferenceEquals(rightSymbol, ValueTypeSymbol.Boolean) &&
            !ReferenceEquals(rightSymbol, ValueTypeSymbol.Date) &&
            !ReferenceEquals(rightSymbol, ValueTypeSymbol.Categorical) &&
            !rightSymbol.IsEnum)
        {
            return false;
        }

        // 只有字符串常量才能尝试转换，对于不是常量的节点，视为可以转换，不在此处报错
        if (!left.Is<StringLiteral>(SyntaxKinds.String, out StringLiteral? stringLiteral))
        {
            result = rightSymbol;
            return true;
        }

        // 尝试转换为Categorical
        if (ReferenceEquals(rightSymbol, ValueTypeSymbol.Categorical))
        {
            result = ValueTypeSymbol.Categorical;
            return TryConvertToCategorical(stringLiteral, out _);
        }

        // 尝试转换为数字
        // 先尝试转换为整数，在尝试浮点数
        if (TryConvert(stringLiteral, SyntaxKinds.Integer, out _))
        {
            // 如果右值是浮点数，返回浮点数，否则，返回整数
            result = ReferenceEquals(rightSymbol, ValueTypeSymbol.Double)
                ? ValueTypeSymbol.Double
                : ValueTypeSymbol.Long;
            return true;
        }

        if (TryConvert(stringLiteral, SyntaxKinds.Double, out _))
        {
            result = ValueTypeSymbol.Double;
            return true;
        }

        return false;
    }
}


internal class IntegerLiteralConverter : ExpressionConverter
{
    public override bool TryConvert(Expression source,
        SyntaxKinds targetKind,
        [MaybeNullWhen(false)] out Expression result)
    {
        result = null;
        IntegerLiteral sourceInteger;

        if (!source.IsOneOfNode(SyntaxKinds.Integer, SyntaxKinds.UnaryExpression) ||
            SyntaxFacts.IsLiteralKind(targetKind))
        {
            return false;
        }

        // 负数在语法树中是 UnaryExpression，并且只转换常量表达式
        if (source.IsNode(SyntaxKinds.UnaryExpression))
        {
            if (!NodeConverter.TryConvertNegativeInteger(source, out IntegerLiteral? convertedNegative))
            {
                return false;
            }

            sourceInteger = convertedNegative;
        }
        else
        {
            sourceInteger = (IntegerLiteral)source;
        }

        result = targetKind switch
        {
            // 在表达式转换时，不主动将非字符串类型转换为字符串
            // SyntaxKinds.String => NodeConverter.ToString(source),
            SyntaxKinds.Integer => sourceInteger,
            SyntaxKinds.Double => NodeConverter.ToDouble(source, sourceInteger.Value),
            SyntaxKinds.Boolean => NodeConverter.ToBoolean(source, sourceInteger.Value != 0),
            _ => null
        };

        if (result != null && result != source)
        {
            result.UpdateFrom(source);
        }

        return result != null;
    }

    public override bool IsConvertible(Expression source,
        ValueTypeSymbol targetType)
    {
        return targetType switch
        {
            { Name: "Long" } => TryConvert(source, SyntaxKinds.Integer, out _),
            { Name: "Double" } => TryConvert(source, SyntaxKinds.Double, out _),
            { Name: "Boolean" } => TryConvert(source, SyntaxKinds.Boolean, out _),
            _ => false
        };
    }


    public override bool ComputeArithmeticOperation(
        Expression left,
        Expression right,
        ITypeSymbol rightSymbol,
        SyntaxKinds operatorKind,
        [MaybeNullWhen(false)] out ITypeSymbol result)
    {
        Debug.Assert(IsArithmeticOperatorKind(operatorKind));
        result = null;

        if (rightSymbol is { IsValueType: false })
        {
            return false;
        }

        // Long | Any | Null
        if (ReferenceEquals(rightSymbol, ValueTypeSymbol.Long) ||
            ValueTypeSymbol.IsAnyOrNull(rightSymbol))
        {
            result = ValueTypeSymbol.Long;
            return true;
        }

        // Double
        if (ReferenceEquals(rightSymbol, ValueTypeSymbol.Double))
        {
            result = ValueTypeSymbol.Double;
            return true;
        }

        // String
        if (!ReferenceEquals(rightSymbol, ValueTypeSymbol.String))
        {
            return false;
        }

        if (StringLiteralConverter.IsConvertible(right, ValueTypeSymbol.Double))
        {
            result = ValueTypeSymbol.Double;
            return true;
        }

        if (!StringLiteralConverter.IsConvertible(right, ValueTypeSymbol.Long))
        {
            return false;
        }

        result = ValueTypeSymbol.Long;
        return true;
    }
}


internal class DoubleLiteralConverter : ExpressionConverter
{
    public override bool TryConvert(Expression source,
        SyntaxKinds targetKind,
        [MaybeNullWhen(false)] out Expression result)
    {
        result = null;

        // 只转换常量
        if (!source.IsNode(SyntaxKinds.Double) || !SyntaxFacts.IsLiteralKind(targetKind))
        {
            return false;
        }

        DoubleLiteral sourceDouble = (DoubleLiteral)source;

        result = targetKind switch
        {
            // 在表达式转换时，不主动将非字符串类型转换为字符串
            // SyntaxKinds.String => NodeConverter.ToString(sourceDouble),
            SyntaxKinds.Integer => NodeConverter.ToInteger(source, (int)sourceDouble.Value),
            SyntaxKinds.Double => sourceDouble,
            SyntaxKinds.Boolean => NodeConverter.ToBoolean(source, sourceDouble.Value != 0),
            _ => null
        };

        if (result != null && result != source)
        {
            result.UpdateFrom(source);
        }

        return result != null;
    }


    public override bool ComputeArithmeticOperation(
        Expression left,
        Expression right,
        ITypeSymbol rightSymbol,
        SyntaxKinds operatorKind,
        [MaybeNullWhen(false)] out ITypeSymbol result)
    {
        Debug.Assert(IsArithmeticOperatorKind(operatorKind));
        result = ValueTypeSymbol.Double;

        if (ValueTypeSymbol.IsNumberType(rightSymbol) ||
            ValueTypeSymbol.IsAnyOrNull(rightSymbol))
        {
            return true;
        }

        // String
        if (ReferenceEquals(rightSymbol, ValueTypeSymbol.String))
        {
            return StringLiteralConverter.IsConvertible(right, ValueTypeSymbol.Double) ||
                   StringLiteralConverter.IsConvertible(right, ValueTypeSymbol.Long);
        }

        result = null;
        return false;
    }
}


public class BooleanLiteralConverter : ExpressionConverter
{
    public override bool TryConvert(Expression source,
        SyntaxKinds targetKind,
        [MaybeNullWhen(false)] out Expression result)
    {
        // 只转换常量
        if (!source.IsNode(SyntaxKinds.Boolean) || !SyntaxFacts.IsLiteralKind(targetKind))
        {
            result = null;
            return false;
        }

        BooleanLiteral sourceBoolean = (BooleanLiteral)source;

        result = targetKind switch
        {
            // 在表达式转换时，不主动将非字符串类型转换为字符串
            // SyntaxKinds.String => NodeConverter.ToString(sourceBoolean),
            SyntaxKinds.Integer => NodeConverter.ToInteger(source, sourceBoolean.Value ? 1 : 0),
            SyntaxKinds.Double => NodeConverter.ToDouble(source, sourceBoolean.Value ? 1 : 0),
            SyntaxKinds.Boolean => sourceBoolean,
            _ => null
        };

        if (result != null && result != source)
        {
            result.UpdateFrom(source);
        }

        return result != null;
    }

    public override bool ComputeArithmeticOperation(
        Expression left,
        Expression right,
        ITypeSymbol rightSymbol,
        SyntaxKinds operatorKind,
        [MaybeNullWhen(false)] out ITypeSymbol result)
    {
        Debug.Assert(IsArithmeticOperatorKind(operatorKind));
        result = null;

        if (ValueTypeSymbol.IsAnyOrNull(rightSymbol))
        {
            result = ValueTypeSymbol.Boolean;
            return true;
        }

        if (ValueTypeSymbol.IsNumberType(rightSymbol))
        {
            result = (ValueTypeSymbol)rightSymbol;
            return true;
        }

        // String
        if (!ValueTypeSymbol.IsString(rightSymbol))
        {
            return false;
        }

        if (StringLiteralConverter.IsConvertible(right, ValueTypeSymbol.Long))
        {
            result = ValueTypeSymbol.Long;
            return true;
        }

        if (StringLiteralConverter.IsConvertible(right, ValueTypeSymbol.Double))
        {
            result = ValueTypeSymbol.Double;
            return true;
        }

        return false;
    }
}


public class NullConverter : ExpressionConverter
{
    public override bool TryConvert(Expression source,
        SyntaxKinds targetKind,
        [MaybeNullWhen(false)] out Expression result)
    {
        result = targetKind switch
        {
            SyntaxKinds.String => NodeConverter.ToString(source),
            SyntaxKinds.Integer => NodeConverter.ToInteger(source, 0),
            SyntaxKinds.Double => NodeConverter.ToDouble(source, 0),
            SyntaxKinds.Boolean => NodeConverter.ToBoolean(source, false),
            SyntaxKinds.Categorical => NodeConverter.ToCategorical(source),
            _ => null
        };

        return result != null;
    }


    public override bool ComputeArithmeticOperation(
        Expression left,
        Expression right,
        ITypeSymbol rightSymbol,
        SyntaxKinds operatorKind,
        [MaybeNullWhen(false)] out ITypeSymbol result)
    {
        Debug.Assert(IsArithmeticOperatorKind(operatorKind));
        result = rightSymbol;
        return true;
    }
}


internal class AnyConverter : ExpressionConverter
{
    public override bool TryConvert(Expression source,
        SyntaxKinds targetKind,
        [MaybeNullWhen(false)] out Expression result)
    {
        result = source;
        return true;
    }

    public override bool ComputeArithmeticOperation(Expression left,
        Expression right,
        ITypeSymbol rightSymbol,
        SyntaxKinds operatorKind,
        [MaybeNullWhen(false)] out ITypeSymbol result)
    {
        result = rightSymbol;
        return true;
    }
}